#include "stdafx.h"
#include "LitScriptEngineNativeAPI.h"
#include "LitScriptEngine.h"
#include "LitCore.h"
#include "LitInputSystem.h"
#include "LitCacheManager.h"
#include "LitXmlSceneManager.h"
#include "LitSceneManager.h"
#include "LitGameStateManager.h"
#include "LitPhysicsManager.h"

namespace Lit
{
	NativeScriptAPICoreFuncsPtr& NativeScriptAPI::getCore(){ return mCore; }
	const NativeScriptAPICoreFuncsPtr& NativeScriptAPI::getCore() const{ return mCore; }
	
	NativeScriptAPICoreFuncs NativeScriptAPI::mBase;
	NativeScriptAPICoreFuncs::NativeScriptAPICoreFuncs( )
	{
		mScene = NULL; mEng = NULL;
	}
	NativeScriptAPICoreFuncs::NativeScriptAPICoreFuncs( ScriptEngine * eng, Ogre::SceneManager * mgr ) : mScene(mgr),mEng( eng ){}
	NativeScriptAPICoreFuncs::NativeScriptAPICoreFuncs(const NativeScriptAPICoreFuncs& rk ) : mScene(rk.mScene),mEng( rk.mEng ){}
	NativeScriptAPICoreFuncs::~NativeScriptAPICoreFuncs(){ }
	std::string		NativeScriptAPICoreFuncs::getAngelVersion(){ return ANGELSCRIPT_VERSION_STRING; }
	std::string		NativeScriptAPICoreFuncs::getVersion(){ return PROJECT_VERSION_STRING; }
	void			NativeScriptAPICoreFuncs::error( const std::string &msg ){ logMessage( "System Error: " + msg  ); messageBox( msg, "Script Error" ); }
	void			NativeScriptAPICoreFuncs::logMessage( const std::string &msg ){ if(mEng)mEng->logMessage( msg ); }
	int				NativeScriptAPICoreFuncs::messageBox( const std::string &msg, const std::string &title ){ return MessageBoxA( 0, msg.c_str(), title.c_str(), MB_ICONINFORMATION ); }
	
	NativeScriptAPICoreFuncs NativeScriptAPI::getSystem(){ return mBase; }

	NativeScriptAPI::NativeScriptAPI(const ScriptEnginePtr& _engine) :engine(_engine) {}
	NativeScriptAPI::~NativeScriptAPI(){ mCore.destroy(); }
	

	NativeScriptAPICoreFuncs core_getSystem( Lit::Root *self ){ return NativeScriptAPI::getSystem(); }
	InputSystem& core_getInput( Lit::Root *self ){ return Lit::InputSystem::Instance().Instance(); }

	void core_Constructor( Lit::Root *self ){	self = &Lit::Root::Instance().Instance();	}
	void core_CConstructor( const Root & is, Lit::Root *self ){	self = &Lit::Root::Instance().Instance();	}

	void InputSystem_Constructor( Lit::InputSystem *self ){	self = &Lit::InputSystem::Instance().Instance();	}
	void InputSystem_CConstructor( const InputSystem & is, Lit::InputSystem *self )	{self = &InputSystem::Instance();	}



	void CacheManager_Constructor( Lit::CacheManager *self ){		self = Lit::Root::Instance().CacheManager();	}
	void XmlSceneManager_Constructor( Lit::XmlSceneManager *self )	{		self = Lit::Root::Instance().XmlSceneManager();	}
	void SceneManager_Constructor( Lit::SceneManager *self )	{		self = Lit::Root::Instance().SceneManager();	}
	void PhysicsManager_Constructor( Lit::PhysicsManager *self )	{		self = Lit::Root::Instance().PhysicsManager();	}
	void GameStateManager_Constructor( Lit::GameStateManager *self )	{		self = Lit::Root::Instance().GameStateManager();	}
	

	void CacheManager_CConstructor( const CacheManager & is, Lit::CacheManager *self ){		self = Lit::Root::Instance().CacheManager();	}
	void XmlSceneManager_CConstructor( const XmlSceneManager & is, Lit::XmlSceneManager *self )	{		self = Lit::Root::Instance().XmlSceneManager();	}
	void SceneManager_CConstructor( const SceneManager & is, Lit::SceneManager *self )	{		self = Lit::Root::Instance().SceneManager();	}
	void PhysicsManager_CConstructor( const PhysicsManager & is, Lit::PhysicsManager *self )	{		self = Lit::Root::Instance().PhysicsManager();	}
	void GameStateManager_CConstructor( const GameStateManager & is, Lit::GameStateManager *self )	{		self = Lit::Root::Instance().GameStateManager();	}
	
	void NativeScriptAPI::registerCoreInputSystem()
	{
		int r = 0;
		r = engine->registerEnum("KeyModifier"); assert( r>=0 );
		r = engine->registerEnum("KeyEnum"); assert( r>=0 );

		r = engine->registerEnumValue( "KeyModifier", "Key_Control", Lit::Key_Control ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyModifier", "Key_LAlt", Lit::Key_LAlt ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyModifier", "Key_RAlt", Lit::Key_RAlt ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyModifier", "Key_Shift", Lit::Key_Shift ); assert( r>=0 );

		r = engine->registerEnumValue( "KeyEnum", "Key_None", Lit::Key_None ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_A", Lit::Key_A ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_B", Lit::Key_B ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_C", Lit::Key_C ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_D", Lit::Key_D ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_E", Lit::Key_E ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_F", Lit::Key_F ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_G", Lit::Key_G ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_H", Lit::Key_H ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_I", Lit::Key_I ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_J", Lit::Key_J ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_K", Lit::Key_K ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_L", Lit::Key_L ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_M", Lit::Key_M ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_N", Lit::Key_N ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_O", Lit::Key_O ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_P", Lit::Key_P ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Q", Lit::Key_Q ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_R", Lit::Key_R ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_S", Lit::Key_S ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_T", Lit::Key_T ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_U", Lit::Key_U ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_V", Lit::Key_V ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_W", Lit::Key_W ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_X", Lit::Key_X ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Y", Lit::Key_Y ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Z", Lit::Key_Z ); assert( r>=0 );

		r = engine->registerEnumValue( "KeyEnum", "Key_0", Lit::Key_0 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_1", Lit::Key_1 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_2", Lit::Key_2 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_3", Lit::Key_3 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_4", Lit::Key_4 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_5", Lit::Key_5 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_6", Lit::Key_6 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_7", Lit::Key_7 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_8", Lit::Key_8 ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_9", Lit::Key_9 ); assert( r>=0 );

		r = engine->registerEnumValue( "KeyEnum", "Key_LBracket", Lit::Key_LBracket ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_RBracket", Lit::Key_RBracket ); assert( r>=0 );
		
		r = engine->registerEnumValue( "KeyEnum", "Key_LBrace", Lit::Key_LBrace ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_RBrace", Lit::Key_RBrace ); assert( r>=0 );

		r = engine->registerEnumValue( "KeyEnum", "Key_ArrowUp", Lit::Key_ArrowUp ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_ArrowDown", Lit::Key_ArrowDown ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_ArrowLeft", Lit::Key_ArrowLeft ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_ArrowRight", Lit::Key_ArrowRight ); assert( r>=0 );
		
		r = engine->registerEnumValue( "KeyEnum", "Key_LParenthesis", Lit::Key_LParenthesis ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_RParenthesis", Lit::Key_RParenthesis ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Dot", Lit::Key_Dot ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_SemiColon", Lit::Key_SemiColon ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Coma", Lit::Key_Coma ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Colon", Lit::Key_Colon ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Bar", Lit::Key_Bar ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Delete", Lit::Key_Delete ); assert( r>=0 );
		
		r = engine->registerEnumValue( "KeyEnum", "Key_Backspace", Lit::Key_Backspace ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Return", Lit::Key_Return ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Space", Lit::Key_Space ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_Quote", Lit::Key_Quote ); assert( r>=0 );
		r = engine->registerEnumValue( "KeyEnum", "Key_DoubleQuote", Lit::Key_DoubleQuote ); assert( r>=0 );
		
		ScSingleton<Lit::InputSystem>( *engine, "InputSystem" )
			.defAccessor( asFUNCTION( Lit::InputSystem::Instance ) )
			.defMember( "bool isModifierDown( KeyModifier ) const", asMETHOD(InputSystem, isModifierDown), asCALL_THISCALL )
			.defMember( "bool isKeyDown( KeyEnum ) const", asMETHOD(InputSystem, isKeyDown), asCALL_THISCALL )
			.defMember( "bool isKeyUp( KeyEnum ) const", asMETHOD(InputSystem, isKeyDown), asCALL_THISCALL );
		ScType<Root>( *engine, "Root", false )
			.defMember( "InputSystem& getInputManager()", asFUNCTION(InputSystem::Instance), asCALL_CDECL );
	}
	void NativeScriptAPI::registerCore( Ogre::SceneManager * mgr ){
		engine->setDefaultNamespace( "Lit" );
		int r = SC_OBJECT( engine->data(), "System", NativeScriptAPICoreFuncs, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_AK ); assert( r >= 0 );
		r = SC_OBJECT_CONSTRUCT( engine->data(), "System", "void f(const System &in)", asFUNCTION( NativeScriptAPICoreFuncs::copyConstructor ), asCALL_CDECL_OBJLAST ); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "::string getVersion()", asMETHOD(NativeScriptAPICoreFuncs,getVersion), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "::string getAngelVersion()", asMETHOD(NativeScriptAPICoreFuncs,getAngelVersion), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "void logMessage(const ::string &in)", asMETHOD(NativeScriptAPICoreFuncs,logMessage), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "void error(const ::string &in)", asMETHOD(NativeScriptAPICoreFuncs,error), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "void messageBox(const ::string &in, const ::string &in title = ::string() )", asMETHOD(NativeScriptAPICoreFuncs,messageBox), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "Ogre::SceneManager getSceneManager(const ::string &in name) const", asMETHODPR(NativeScriptAPICoreFuncs,getSceneManager,(const std::string &) const, ScriptWrappers::SceneMgrWrp), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "Ogre::SceneManager getSceneManager() const", asMETHODPR(NativeScriptAPICoreFuncs,getSceneManager,() const, ScriptWrappers::SceneMgrWrp), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "Ogre::SceneManager createSceneManager(const ::string &in name)", asMETHOD(NativeScriptAPICoreFuncs,createSceneManager), asCALL_THISCALL); assert( r >= 0 );
		r = SC_OBJECT_METHOD( engine->data(), "System", "void destroySceneManager( Ogre::SceneManager &out )", asMETHOD(NativeScriptAPICoreFuncs,destroySceneManager), asCALL_THISCALL); assert( r >= 0 );
		
		r = SC_OBJECT( engine->data(), "Root", Root, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA ); assert( r >= 0 );
		r = SC_OBJECT( engine->data(), "CacheManager", CacheManager, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK ); assert( r >= 0 );
		r = SC_OBJECT( engine->data(), "XmlSceneManager", XmlSceneManager, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK ); assert( r >= 0 );
		r = SC_OBJECT( engine->data(), "SceneManager", SceneManager, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK ); assert( r >= 0 );
		r = SC_OBJECT( engine->data(), "GameStateManager", GameStateManager, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK ); assert( r >= 0 );
		r = SC_OBJECT( engine->data(), "PhysicsManager", PhysicsManager, asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK ); assert( r >= 0 );

		r = SC_OBJECT_CONSTRUCT( engine->data(), "CacheManager", "void f()", asFUNCTION(CacheManager_Constructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "XmlSceneManager", "void f()", asFUNCTION(XmlSceneManager_Constructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "SceneManager", "void f()", asFUNCTION(SceneManager_Constructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "GameStateManager", "void f()", asFUNCTION(GameStateManager_Constructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "PhysicsManager", "void f()", asFUNCTION(PhysicsManager_Constructor), asCALL_CDECL_OBJLAST ); assert(r>=0);

		r = SC_OBJECT_CONSTRUCT( engine->data(), "CacheManager", "void f( const CacheManager &in )", asFUNCTION(CacheManager_CConstructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "XmlSceneManager", "void f( const XmlSceneManager &in )", asFUNCTION(XmlSceneManager_CConstructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "SceneManager", "void f( const SceneManager &in )", asFUNCTION(SceneManager_CConstructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "GameStateManager", "void f( const GameStateManager &in )", asFUNCTION(GameStateManager_CConstructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "PhysicsManager", "void f( const PhysicsManager &in )", asFUNCTION(PhysicsManager_CConstructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		
		r = SC_OBJECT_CONSTRUCT( engine->data(), "Root", "void f()", asFUNCTION(core_Constructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		r = SC_OBJECT_CONSTRUCT( engine->data(), "Root", "void f( const Root &in )", asFUNCTION(core_CConstructor), asCALL_CDECL_OBJLAST ); assert(r>=0);
		
		r = SC_OBJECT_METHOD( engine->data(), "Root", "System getSystem()", asFUNCTION(core_getSystem), asCALL_CDECL_OBJLAST ); assert(r>=0);

		r = SC_OBJECT_METHOD( engine->data(), "Root", "::string getVersion() const", asMETHOD(Lit::Root, getVersion), asCALL_THISCALL ); assert(r>=0);
		r = SC_OBJECT_METHOD( engine->data(), "Root", "uint32 getVersionMajor() const", asMETHOD(Lit::Root, getVersionMajor), asCALL_THISCALL ); assert(r>=0);
		r = SC_OBJECT_METHOD( engine->data(), "Root", "uint32 getVersionMinor() const", asMETHOD(Lit::Root, getVersionMinor), asCALL_THISCALL ); assert(r>=0);
		r = SC_OBJECT_METHOD( engine->data(), "Root", "uint32 getVersionBuild() const", asMETHOD(Lit::Root, getVersionBuild), asCALL_THISCALL ); assert(r>=0);
		r = SC_OBJECT_METHOD( engine->data(), "Root", "uint32 getVersionRevision() const", asMETHOD(Lit::Root, getVersionRevision), asCALL_THISCALL ); assert(r>=0);
		r = SC_OBJECT_METHOD( engine->data(), "Root", "Ogre::Real getFrameTime() const", asMETHOD(Lit::Root, getFrameTime), asCALL_THISCALL ); assert(r>=0);
		
		registerCoreInputSystem();
		
		engine->setDefaultNamespace( "" );
	}
	void NativeScriptAPI::bind( Ogre::SceneManager * mgr ){
		mCore = new NativeScriptAPICoreFuncs( *engine, mgr );
		_setBaseFuncs( **mCore );
		registerOGRE( mgr );
		registerCore( mgr );
	}
};